///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include <Texture/TGATextureLoader.h>
#include <File/File.h>
#include <Util.h>

//-----------------------------------------------------------------------------

#define INVERTED_BIT            (1 << 5)

#pragma pack(push,x1)                            // Byte alignment (8-bit)
#pragma pack(1)

typedef struct
{
   unsigned char  IdSize,
                  MapType,
                  ImageType;
   unsigned short PaletteStart,
                  PaletteSize;
   unsigned char  PaletteEntryDepth;
   unsigned short X,
                  Y,
                  Width,
                  Height;
   unsigned char  ColorDepth,
                  Descriptor;
         
} TGA_HEADER;

#pragma pack(pop,x1)

//-----------------------------------------------------------------------------

TGATextureLoader::TGATextureLoader ()
{
	RegisterLoader( this );
}

//-----------------------------------------------------------------------------

TGATextureLoader::~TGATextureLoader ()
{
	UnregisterLoader( this );
}

//-----------------------------------------------------------------------------

bool	TGATextureLoader::CanLoad(File* textureFile)
{
	if( !textureFile->IsOpen() )
	{
		return false;
	}

	textureFile->Seek( 0 );

	TGA_HEADER   Header;
	textureFile->Read( &Header, sizeof(TGA_HEADER), 1 );

	if( Header.ColorDepth != 8
		&& Header.ColorDepth != 24
		&& Header.ColorDepth != 32
		)
	{
		return false;
	}

	return true;
}

//-----------------------------------------------------------------------------

void invert( u8** data, u8 bpp, u16 width, u16 height )
{
	u32 i=0;
	u32 x,y,b;
	u32 Index;
	u8 aux;
	u8* buffer = (*data);
	for ( y = 0; y < (u32)(height / 2) ; y++ )
	{
		for( x = 0; x < width; x++ )
		{
			Index = (height - 1 - y) * width + x;

			for( b = 0; b < bpp; b++ )
			{
				aux = buffer[(i * bpp) + b];
				buffer[(i * bpp) + b] = buffer[ (Index * bpp) + b ];
				buffer[ (Index * bpp) + b ] = aux;
			}

			i++;
		}
	}
}

//-----------------------------------------------------------------------------

s32		TGATextureLoader::GetData(File* textureFile, void** data, u16& width, u16& height, GLenum& format, GLenum& type)
{
	if( !CanLoad( textureFile ) )
	{
		return -1;
	}

	textureFile->Seek( 0 );

	TGA_HEADER   Header;
	textureFile->Read( &Header, sizeof(TGA_HEADER), 1 );

	width = Header.Width;
	height = Header.Height;

	u8 *buffer = NULL;
	buffer = (u8*) malloc( Header.ColorDepth / 8 * width * height);

	switch(Header.ColorDepth)
	{
		case 8:
			format = GL_LUMINANCE;
			type = GL_UNSIGNED_BYTE;
			break;

		case 24:
			format = GL_BGR;
			type = GL_UNSIGNED_BYTE;
			break;

		case 32:
			format = GL_BGRA;
			type = GL_UNSIGNED_BYTE;
			break;

		default:
			return -1;
	}

	if( !buffer )
	{
		return -1;
	}
	else
	{
		s32 read = (s32) textureFile->Read(buffer, Header.ColorDepth / 8, width * height);

		if(!(Header.Descriptor & INVERTED_BIT))
		{
			invert( &buffer, Header.ColorDepth / 8, width, height );
		}

		(*data) = (void*) buffer;

		return read;
	}		

	return 0;
}

//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
